package com.by.rpc.config;

import com.by.log.Logger;
import com.by.log.LoggerFactory;
import com.by.rpc.dto.ServiceInstance;
import com.by.rpc.netty.RpcServer;
import com.by.rpc.provider.ServiceProvider;
import com.by.rpc.registry.HeartbeatChecker;
import com.by.rpc.registry.RedisServiceRegistry;
import com.by.rpc.registry.ServiceRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * RPC注册中心自动配置类
 */
@Configuration
@EnableConfigurationProperties(RpcProperties.class)
public class RegistryAutoConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(RegistryAutoConfiguration.class);

    @Autowired
    private RpcProperties rpcProperties;

    @Bean
    @ConditionalOnMissingBean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        StringRedisSerializer stringSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringSerializer);
        template.setHashKeySerializer(stringSerializer);
        GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
        template.setValueSerializer(jsonSerializer);
        template.setHashValueSerializer(jsonSerializer);
        template.afterPropertiesSet();
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean(RedisTemplate.class)
    public ServiceRegistry serviceRegistry(RedisTemplate<String, Object> redisTemplate) {
        return new RedisServiceRegistry(redisTemplate);
    }

    @Bean(initMethod = "start",destroyMethod = "stop")
    @ConditionalOnMissingBean
    @ConditionalOnBean(ServiceRegistry.class)
    public HeartbeatChecker heartbeatChecker(ServiceRegistry serviceRegistry, ServiceInstance localServiceInstance) {
        return new HeartbeatChecker(serviceRegistry, localServiceInstance);
    }

    @Bean
    @ConditionalOnMissingBean
    public ServiceInstance localServiceInstance() {
        ServiceInstance serviceInstance = new ServiceInstance();
        String serviceName = rpcProperties.getServiceName();
        if (serviceName != null && !serviceName.isEmpty()) {
            serviceInstance.setServiceName(serviceName);
        } else {
            String scanPackage = rpcProperties.getScanPackage();
            if (scanPackage != null) {
                if (scanPackage.contains(".user.")) {
                    serviceInstance.setServiceName("user-service");
                } else if (scanPackage.contains(".product.")) {
                    serviceInstance.setServiceName("product-service");
                } else if (scanPackage.contains(".order.")) {
                    serviceInstance.setServiceName("order-service");
                } else {
                    serviceInstance.setServiceName(scanPackage);
                }
            } else {
                serviceInstance.setServiceName("unknown-service");
            }
        }
        serviceInstance.setVersion("1.0.0");
        serviceInstance.setGroup("default");
        serviceInstance.setHost(rpcProperties.getServerHost());
        serviceInstance.setPort(rpcProperties.getServerPort());
        serviceInstance.setRegisterTime(System.currentTimeMillis());
        return serviceInstance;
    }

    @Bean
    @ConditionalOnMissingBean
    public ServiceProvider serviceProvider() {
        return new ServiceProvider(rpcProperties);
    }

    @Bean(initMethod = "start", destroyMethod = "close")
    @ConditionalOnMissingBean
    public RpcServer rpcServer(ServiceProvider serviceProvider) {
        logger.info("Starting RPC server on port {}", rpcProperties.getServerPort());
        return new RpcServer(rpcProperties.getServerPort(), serviceProvider);
    }

}